using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace Scan
{
    public class GradientButton : Control
    {

        bool bGetFocus;
        bool bPressed;


        // Used to double-buffer our drawing to avoid flicker
        // between painting the background, border, focus-rect
        // and the text of the control.
        private Bitmap DoubleBufferImage
        {
            get
            {
                if (bmDoubleBuffer == null)
                    bmDoubleBuffer = new Bitmap(
                        this.ClientSize.Width,
                        this.ClientSize.Height);
                return bmDoubleBuffer;
            }
            set
            {
                if (bmDoubleBuffer != null)
                    bmDoubleBuffer.Dispose();
                bmDoubleBuffer = value;
            }
        }
        private Bitmap bmDoubleBuffer;

        // Called when the control is resized. When that happens,
        // recreate the bitmap used for double-buffering.
        protected override void OnResize(EventArgs e)
        {
            DoubleBufferImage = new Bitmap(
                this.ClientSize.Width,
                this.ClientSize.Height);
            base.OnResize(e);
        }

        // Called when the control gets focus. Need to repaint
        // the control to ensure the focus rectangle is drawn correctly.
        protected override void OnGotFocus(EventArgs e)
        {
            bGetFocus = true;
            base.OnGotFocus(e);
            this.Invalidate();
        }
        //
        // Called when the control loses focus. Need to repaint
        // the control to ensure the focus rectangle is removed.
        protected override void OnLostFocus(EventArgs e)
        {
            bGetFocus = false;
            base.OnLostFocus(e);
            this.Invalidate();
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (this.Capture)
            {
                Point coord = new Point(e.X, e.Y);
                if (this.ClientRectangle.Contains(coord) !=
                    this.ClientRectangle.Contains(lastCursorCoordinates))
                {
                    DrawButton(this.ClientRectangle.Contains(coord));
                }
                lastCursorCoordinates = coord;
            }
            base.OnMouseMove(e);
        }

        // The coordinates of the cursor the last time
        // there was a MouseUp or MouseDown message.
        Point lastCursorCoordinates;

        protected override void OnMouseDown(MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                this.bPressed = true;
                // Start capturing the mouse input
                this.Capture = true;
                // Get the focus because button is clicked.
                this.Focus();

                // draw the button
                DrawButton(true);
            }

            base.OnMouseDown(e);
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            this.bPressed = false;

            this.Capture = false;

            DrawButton(false);

            base.OnMouseUp(e);
        }

        protected override void OnEnabledChanged(EventArgs e)
        {
            base.OnEnabledChanged(e);
            base.Invalidate();
        }

        bool bGotKeyDown = false;
        protected override void OnKeyDown(KeyEventArgs e)
        {
            bGotKeyDown = true;
            switch (e.KeyCode)
            {
                case Keys.Space:
                case Keys.Enter:
                    DrawButton(true);
                    break;
                case Keys.Up:
                case Keys.Left:
                    this.Parent.SelectNextControl(this, false, false, true, true);
                    break;
                case Keys.Down:
                case Keys.Right:
                    this.Parent.SelectNextControl(this, true, false, true, true);
                    break;
                default:
                    bGotKeyDown = false;
                    base.OnKeyDown(e);
                    break;
            }
        }

        protected override void OnKeyUp(KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Space:
                case Keys.Enter:
                    if (bGotKeyDown)
                    {
                        DrawButton(false);
                        OnClick(EventArgs.Empty);
                        bGotKeyDown = false;
                    }
                    break;
                default:
                    base.OnKeyUp(e);
                    break;
            }
        }

        // Override this method with no code to avoid flicker.
        protected override void OnPaintBackground(PaintEventArgs e)
        {
        }
        protected override void OnPaint(PaintEventArgs e)
        {
             DrawButton(e.Graphics, this.Capture &&
                (this.ClientRectangle.Contains(lastCursorCoordinates)));
        }

        //
        // Gets a Graphics object for the provided window handle
        //  and then calls DrawButton(Graphics, bool).
        //
        // If pressed is true, the button is drawn
        // in the depressed state.
        void DrawButton(bool pressed)
        {
            try
            {
                Graphics gr = this.CreateGraphics();
                DrawButton(gr, pressed);
                gr.Dispose();
            }
            catch
            {
                // when exit application...this exception occurred
            }
        }

        // Draws the button on the specified Grapics
        // in the specified state.
        //
        // Parameters:
        //  gr - The Graphics object on which to draw the button.
        //  pressed - If true, the button is drawn in the depressed state.
        void DrawButton(Graphics gr, bool pressed)
        {
            // Get a Graphics object from the background image.
            Graphics gr2 = Graphics.FromImage(DoubleBufferImage);

            SolidBrush br = new SolidBrush(SystemColors.Control);
            gr2.FillRectangle(br, this.ClientRectangle);
            br.Dispose();

            if (this.Site != null && this.Site.DesignMode)
            {
            }
            else
            {
                IntPtr hDC = gr2.GetHdc();

                if (!this.Enabled)
                {
                    IntPtr inActBorderPen = Win32.CreatePen(Win32.PS_SOLID, 1, Win32.RGB(160, 160, 160));

                    IntPtr hOldPen = Win32.SelectObject(hDC, inActBorderPen);
                    IntPtr hOldBrush = Win32.SelectObject(hDC, Win32.GetStockObject(Win32.WHITE_BRUSH));

                    Win32.RoundRect(hDC, 0, 0, this.Width, this.Height, 6, 6);

                    Win32.SelectObject(hDC, hOldPen);
                    Win32.SelectObject(hDC, hOldBrush);

                    Win32.DeleteObject(inActBorderPen);


                    IntPtr inActBgBrush = Win32.CreateSolidBrush(Win32.RGB(236, 236, 236));
                    Win32.RECT rc = new Win32.RECT(2, 2, this.Width - 2, this.Height - 2);

                    Win32.FillRect(hDC, ref rc, inActBgBrush);

                    Win32.DeleteObject(inActBgBrush);
                }
                else
                {

                    IntPtr borderPen = Win32.CreatePen(Win32.PS_SOLID, 1, Win32.RGB(112, 112, 112));

                    IntPtr hOldPen = Win32.SelectObject(hDC, borderPen);
                    IntPtr hOldBrush = Win32.SelectObject(hDC, Win32.GetStockObject(Win32.WHITE_BRUSH));

                    Win32.RoundRect(hDC, 0, 0, this.Width, this.Height, 6, 6);

                    Win32.SelectObject(hDC, hOldPen);
                    Win32.SelectObject(hDC, hOldBrush);

                    Win32.DeleteObject(borderPen);


                    Win32.GRADIENT_RECT[] gra = new Win32.GRADIENT_RECT[2] { new Win32.GRADIENT_RECT(0, 1), new Win32.GRADIENT_RECT(2, 3)};

                    Win32.TRIVERTEX[] tva = new Win32.TRIVERTEX[4];
                    tva[0] = new Win32.TRIVERTEX(2, 2, 0xf2, 0xf2, 0xf2, 0x00);
                    tva[1] = new Win32.TRIVERTEX(Width - 2, Height / 2, 0xEB, 0xEB, 0xEB, 0x00);
                    tva[2] = new Win32.TRIVERTEX(2, Height / 2, 0xDD, 0xDD, 0xDD, 0x00);
                    tva[3] = new Win32.TRIVERTEX(Width - 2, Height - 2, 0xCF, 0xCF, 0xCF, 0x00);

                    Win32.GradientFill(hDC, tva, 4, gra, 2, Win32.GRADIENT_FILL_RECT_V);

                }

                gr2.ReleaseHdc(hDC);
            }

            if (this.bGetFocus)
            {
                Pen pen = new Pen(Color.FromArgb(112, 112, 112));
                pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;

                Rectangle rc = new Rectangle(3, 3, Width - 7, Height - 7);
                gr2.DrawRectangle(pen, rc);

                pen.Dispose();
            }

            Rectangle rc2 = this.ClientRectangle;

            SizeF textSize = gr2.MeasureString(this.Text, this.Font);
            if (textSize.Width > rc2.Width)
            {
                rc2.Offset(0, rc2.Height / 2 - (int)textSize.Height);
            }
            else
            {
                rc2.Offset(0, (int)((rc2.Height - textSize.Height) / 2));
            }
            
            if (bPressed)
            {
                rc2.Offset(1, 1);
            }
            SolidBrush brush;
            if (this.Enabled)
            {
                brush = new SolidBrush(ForeColor);
            }
            else
            {
                brush = new SolidBrush(Color.FromArgb(170, 170, 170));
            }

            StringFormat format = new StringFormat();
            format.Alignment = StringAlignment.Center;
            //format.LineAlignment = StringAlignment.Center;

            gr2.DrawString(this.Text, this.Font, brush, rc2, format);

            brush.Dispose();

            // Draw from the background image onto the screen.
            gr.DrawImage(DoubleBufferImage, 0, 0);
            gr2.Dispose();
        }

        public void PerformClick()
        {
            if (this.Enabled && this.Visible)
            {
                this.OnClick(new EventArgs());
            }
        }
    }

}
